Напомнить, что эта лекция — переход от консольного программирования к событийно-ориентированному. Спросить студентов, кто работал с GUI-программированием раньше.
Быстро пробежать по плану. Обратить внимание, что первая половина — Windows (WinAPI), вторая — Linux. Основной фокус на концепциях, а не на синтаксисе конкретного API.
Это студентам знакомо — всё, что они писали до этого. Подчеркнуть: программа сама управляет потоком выполнения, ждёт ввода пользователя. Задать вопрос: «Что произойдёт, если пользователь введёт букву вместо числа?»
Ключевое отличие от консоли: программа не управляет потоком, а реагирует на события. Показать архитектуру слоями — каждый слой абстрагирует нижний. Спросить: «Может ли приложение напрямую писать в видеопамять?»
Обратить внимание на строку «Автоматизация»: консольные программы проще скриптить (pipes, redirects). GUI-автоматизация требует специальных инструментов (Selenium, AutoHotkey). Задать вопрос: «Когда лучше выбрать консольное приложение?»
Важная аналогия: класс окна в Windows — как класс в ООП. Определяет общие свойства, а конкретные окна — экземпляры. Подчеркнуть, что WindowProc — это «метод» класса, общий для всех окон этого класса. Частая ошибка: забыть обнулить структуру {0}.
Элементы управления в WinAPI — это тоже окна! CreateWindow создаёт и кнопку, и поле ввода. HMENU для идентификатора — нетипичное использование, может запутать. Показать, как дочерние окна отправляют WM_COMMAND родителю.
GWLP_USERDATA — распространённый паттерн для хранения указателя на C++ объект (this) в WinAPI. После изменения стиля обязательно нужен SetWindowPos с SWP_FRAMECHANGED, иначе изменения не отобразятся — типичная ошибка студентов. Подчеркнуть разницу: SetWindowLong — данные класса, SetWindowLongPtr — для 64-битной совместимости.
Ключевой переход мышления: от «программа говорит пользователю что делать» к «пользователь говорит программе что делать». Аналогия с рестораном: официант (диспетчер) принимает заказы (события) и передаёт на кухню (обработчик). Спросить: «Какая структура данных подходит для очереди сообщений?»
Три функции в цикле — три разных роли: GetMessage (получить), TranslateMessage (преобразовать), DispatchMessage (отправить). TranslateMessage превращает WM_KEYDOWN в WM_CHAR — спросить, зачем это нужно. PeekMessage — для игр и анимации, где нельзя блокировать. Частая ошибка: забыть проверить WM_QUIT при использовании PeekMessage.
Показать скелет WinAPI-приложения — это «Hello World» для Windows. Пять шагов всегда одни и те же. Задать вопрос: «Что будет, если убрать ShowWindow?» — окно создастся, но останется невидимым. Подчеркнуть: CreateWindowEx возвращает HWND, а не создаёт визуально — для этого нужен ShowWindow.
Оконная процедура вызывается ОС, а не программой — это callback. DefWindowProc обрабатывает всё, что мы не обработали — без него окно не будет работать. WM_DESTROY → PostQuitMessage — стандартный паттерн завершения. Типичная ошибка студентов: return 0 вместо DefWindowProc в default, из-за чего окно не двигается и не ресайзится.
wParam и lParam — «универсальные» параметры, смысл которых зависит от конкретного сообщения. Это историческое ограничение: в 16-битной Windows wParam был 16 бит, lParam — 32. Важно: MSG содержит поля time и pt — спросить, зачем они нужны (для отладки и логирования).
Спросить: «Может ли одно приложение отправить сообщение в окно другого?» — да, и это основа многих техник (в т.ч. вредоносных). Подчеркнуть три уровня: железо → ОС → приложение. Упомянуть, что таймер (WM_TIMER) — тоже источник сообщений, хотя его никто не нажимает.
Ключевое отличие: PostMessage кладёт в очередь и сразу возвращается, SendMessage дожидается обработки. SendMessage может вызвать дедлок, если два окна отправляют друг другу сообщения. Если hWnd = NULL в PostMessage, сообщение получают все окна с одинаковым ID (broadcast).
Распространённое заблуждение: «у каждого окна своя очередь». На самом деле очередь привязана к потоку, создавшему окно. Поэтому GUI-поток не должен блокироваться — иначе перестанут обрабатываться все окна этого потока. Спросить: «Что будет, если GUI-поток сделать sleep(5)?»
GetMessage блокирует поток — приложение «спит» и не потребляет CPU. PeekMessage позволяет делать работу между обработкой событий (игры, анимация). Фильтрация по диапазону полезна для обработки только ввода с клавиатуры (WM_KEYFIRST..WM_KEYLAST).
WM_KEYDOWN даёт виртуальный код (независимый от раскладки), WM_CHAR — уже символ с учётом языка. TranslateMessage в цикле сообщений именно и создаёт WM_CHAR из WM_KEYDOWN. Спросить: «Как определить, нажат ли Shift?» — через GetKeyState в обработчике WM_KEYDOWN.
Координаты мыши в lParam — LOWORD и HIWORD, но для корректной работы с 64-битными системами нужно использовать макросы GET_X_LPARAM и GET_Y_LPARAM. Частая ошибка: прямое использование (short)lParam. WM_MOUSEMOVE генерируется часто — рекомендовать использовать флаг отслеживания для оптимизации отрисовки.
WM_COMMAND — универсальный обработчик для меню, кнопок и акселераторов. Все они приходят в одно место. LOWORD(wParam) — идентификатор элемента. Для более сложных элементов (ListView, TreeView) используется WM_NOTIFY. Спросить: «Как отличить, от кнопки или от меню пришёл WM_COMMAND?» — через HIWORD(wParam).
Это большой слайд — выделить на него больше времени (5-7 мин). Сравнить с WinAPI: в Linux нет единого API, есть много слоёв. Показать параллель: WinAPI-сообщения ≈ X11-события ≈ GTK-signals ≈ Qt-signals/slots. Упомянуть, что в реальной работе на Linux почти никто не пишет на Xlib напрямую — используют GTK или Qt.
Пробежать по пунктам, попросить студентов назвать по одному ключевому слову к каждому пункту. Убедиться, что концепция «сообщения» как универсального механизма коммуникации в GUI понятна — она общая для Windows и Linux.
Рекомендовать студентам ответить на вопросы устно в парах перед следующей лекцией. Вопросы 5 и 7 — самые важные для понимания. Можно дать 2-3 минуты на обсуждение в парах прямо на лекции.
Задания рассчитаны на 8 часов самостоятельной работы. Рекомендовать начать с GTK (задание 2) — оно проще для компиляции на Linux. Задание 3 с xev/xprop можно выполнить прямо в терминале без написания кода — хороший способ познакомиться с X11-сообщениями визуально. Для задания 4 можно использовать Qt Creator.